#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"
#include <stdlib.h>
#include "app_bluetooth.h"
#include <unistd.h>


static int set_block_mode(SerialDevice *serial, int is_block)
{
    struct termios termios;
    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性（阻塞或非阻塞模式）
    if (is_block)
    {
        termios.c_cc[VTIME] = 0; // 没有读到数据会一直等待
        termios.c_cc[VMIN] = 1; // 至少读取一个字符才返回
    }
    else
    {
        termios.c_cc[VTIME] = 2; // 单位为100ms 等待时间为0.2秒
        termios.c_cc[VMIN] = 0;
    }
   
    // 设置串口属性(只有调用flush后，设置才会生效)
    if (tcsetattr(serial->super.fd, TCSANOW, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }
    return 0;
}
/**
 * 设置为原始模式
 */
static int make_raw(SerialDevice *serial)
{
    struct termios termios;
    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性（原始模式）
    cfmakeraw(&termios);
   
    // 设置串口属性(只有调用flush后，设置才会生效)
    if (tcsetattr(serial->super.fd, TCSANOW, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }
    return 0;
}

/**
 * 初始化
 */
SerialDevice *app_serial_init(char *filename)
{

    // 初始化一个设备
    Device *device = app_device_init(filename);
    if (!device)
    {
        log_error("app_device_init error");
        goto DEVICE_INIT_FAIL;
    }
    // 在设备内存基础扩展出一个串口设备内存
    SerialDevice *serial = realloc(device, sizeof(SerialDevice));
    if (!serial)
    {
        log_error("realloc SerialDevice error");
        goto SERIAL_INIT_FAIL;
    }

    // 设置为原始模式
    if (make_raw(serial) != 0)
    {
        log_error("make_raw error");
        goto SERIAL_INIT_FAIL;
    }

    if (app_serial_setBraudRate(serial, BR_115200) != 0)
    {
        log_error("app_serial_setBraudRate error");
        goto SERIAL_INIT_FAIL;
    }
    if (app_serial_setParity(serial, Parity_None) !=0)
    {
        log_error("app_serial_setParity error");
        goto SERIAL_INIT_FAIL;
    }
    if (app_serial_setStopBits(serial,  StopBits_1) != 0)
    {
        log_error("app_serial_setStopBits error");
        goto SERIAL_INIT_FAIL;
    }

    // 让前面设置的所有属性生效
    tcflush(serial->super.fd, TCIOFLUSH);

    return serial;

SERIAL_INIT_FAIL:
    app_device_close(device);
DEVICE_INIT_FAIL:
    return NULL;
}

/**
 * 设置波特率
 */
int app_serial_setBraudRate(SerialDevice *serial, BraudRate braud_rate)
{

    serial->braud_rate = braud_rate;
    struct termios termios;
    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性（波特率）
    // cfsetispeed(&termios, braud_rate);
    // cfsetospeed(&termios, braud_rate);
    cfsetspeed(&termios, braud_rate);
    // 设置串口属性(只有调用flush后，设置才会生效)
    if (tcsetattr(serial->super.fd, TCSANOW, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }
    return 0;
}
/**
 * 设置校验位
 */
int app_serial_setParity(SerialDevice *serial, Parity parity)
{
    serial->parity = parity;
    struct termios termios;
    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性（校验位）
    termios.c_cflag &= ~(PARENB| PARODD); // 清除校验位
    termios.c_cflag |= parity; // 指定校验位

    // 设置串口属性(只有调用flush后，设置才会生效)
    if (tcsetattr(serial->super.fd, TCSANOW, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }
    return 0;
}

/**
 * 设置停止位
 */
int app_serial_setStopBits(SerialDevice *serial, StopBits stop_bits)
{
    serial->stop_bits = stop_bits;
    struct termios termios;
    // 获取串口属性
    if (tcgetattr(serial->super.fd, &termios) != 0)
    {
        log_error("tcgetattr error");
        return -1;
    }
    // 修改属性（停止位）
    termios.c_cflag &= ~CSTOPB; // 清除停止位
    termios.c_cflag |= stop_bits; // 设置停止位

    // 设置串口属性(只有调用flush后，设置才会生效)
    if (tcsetattr(serial->super.fd, TCSANOW, &termios) != 0)
    {
        log_error("tcsetattr error");
        return -1;
    }
    return 0;
}

/**
 * 设置连接类型
 */
int app_serial_setConnectionType(SerialDevice *serial, ConnectionType conn_type)
{
    serial->super.conn_type = conn_type;
    // 将串口的波特率设置9600, 尝试与蓝牙相连
    app_serial_setBraudRate(serial, BR_9600);
    // 将串口设置为非阻塞模式  =》 如果后面蓝牙没连接上， 会返回-1
    set_block_mode(serial, 0);
    tcflush(serial->super.fd, TCIOFLUSH);

    if (app_bluetooth_status((Device *)serial) == 0) 
    {
        // 初始化蓝牙相关属性
        app_bluetooth_rename((Device*)serial, "atguigu");
        app_bluetooth_setBraudRate((Device*)serial, BT_BR_115200);
        app_bluetooth_setNetID((Device*)serial, "1234");
        app_bluetooth_setMaddr((Device*)serial, "0002");
        app_bluetooth_reset((Device*)serial);
        // 等待蓝牙重启
        sleep(1);
    }

    // 将串口的波特率设置9600, 尝试与蓝牙相连
    app_serial_setBraudRate(serial, BR_115200);
    tcflush(serial->super.fd, TCIOFLUSH);
    // 判断蓝牙是否连接上
    if (app_bluetooth_status((Device *)serial) != 0)
    {
        log_error("bluetooth not connect");
        return -1;
    }

    // 给设备指定postRead和preWrite
    serial->super.funs->post_read = app_bluetooth_postRead;
    serial->super.funs->pre_write = app_bluetooth_preWrite;

    // 完成设置后，将串口设置为阻塞模式
    set_block_mode(serial, 1);
    tcflush(serial->super.fd, TCIOFLUSH);

    return 0;
}